package pl.edu.pb.wi.pwnography.model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import pl.edu.pb.wi.pwnography.parsing.TextFileParser;

/*
 * Proste opakowanie na dane.
 */
public class DataHolder {
    protected Map<String, List<Object>> data;
    protected Integer rowCount = null;

    public Map<String, List<Object>> getData() {
	return data;
    }

    public void insertData(Map<String, List<Object>> data) {
	this.data.putAll(data);
    }

    public List<String> getColumnNames() {
	List<String> names = new ArrayList<String>(data.keySet());
	sortMyColumnNames(names);
	return names;
    }

    public List<Object> getColumnValues(String columnName) {
	return data.get(columnName);
    }

    public List<String> getFloatTypeColumnNames() {
	List<String> floatColumns = new ArrayList<String>();
	for (String colName : getColumnNames())
	    if (getColumnValues(colName).get(0) instanceof Float)
		floatColumns.add(colName);

	sortMyColumnNames(floatColumns);

	return floatColumns;
    }

    /**
     * Początkowo metoda służyła do zwracania jedynie kolumn z obiektami typu
     * String. Niestety, okazało się, że klasa w cale nie musi być typu String.
     * Może być także wartością liczbową. Z tego względu metoda ta zwraca
     * wszystkie kolumny pliku.
     * 
     * @return @see getColumnNames()
     */
    // public List<String> getAllColumnNames() {
    // return getColumnNames();
    // }

    public List<String> getStringTypeColumnNames() {
	List<String> stringColumns = new ArrayList<String>();
	for (String colName : getColumnNames())
	    if (getColumnValues(colName).get(0) instanceof String)
		stringColumns.add(colName);

	sortMyColumnNames(stringColumns);

	return stringColumns;
    }

    private void sortMyColumnNames(List<String> names) {
	Collections.sort(names, new Comparator<String>() {
	    @Override
	    public int compare(String o1, String o2) {
		try {
		    Integer tempOne = Integer.parseInt(o1.replace(
			    TextFileParser.COLUMN_NAME, "").trim());
		    Integer tempTwo = Integer.parseInt(o2.replace(
			    TextFileParser.COLUMN_NAME, "").trim());

		    return tempOne.compareTo(tempTwo);
		} catch (Exception ex) {
		    return o1.compareTo(o2);
		}
	    }
	});
    }

    public List<String> getDistinctColumnValues(String stringColumnName) {
	if (!getColumnNames().contains(stringColumnName))
	    return null;

	Set<String> distinctValues = new HashSet<String>();
	for (Object val : getColumnValues(stringColumnName))
	    distinctValues.add(val.toString());

	return new ArrayList<String>(distinctValues);
    }

    protected void setRowCount() {
	if (data == null)
	    return;

	int size = -1;
	while (data.values().iterator().hasNext()) {
	    size = data.values().iterator().next().size();
	    break;
	}

	rowCount = size;
    }

    public int getRowCount() {
	// if (rowCount != null)
	// return rowCount;
	//
	// int size = -1;
	// while (data.values().iterator().hasNext()) {
	// size = data.values().iterator().next().size();
	// break;
	// }
	//
	// rowCount = size;
	// return size;
	return rowCount;
    }

    public Object getCell(String columnName, int rowNumber) {
	// if (rowNumber > (getRowCount() - 1) || rowNumber < 0) {
	// return null;
	// } else {
	return data.get(columnName).get(rowNumber);
	// }
    }

    public Object[][] getAsArray() {
	List<String> columns = getColumnNames();
	int rowCount = getRowCount();

	Object[][] resultArray = new Object[rowCount + 1][columns.size()];

	resultArray[0] = columns.toArray();
	Object cell;
	for (int row = 0; row < rowCount; ++row) {
	    for (int col = 0; col < columns.size(); ++col) {
		cell = getCell(columns.get(col), row);
		if (cell instanceof Float
			&& ((Float) cell).floatValue() % 1 == 0) {
		    cell = ((Float) cell).longValue();
		}
		resultArray[row + 1][col] = cell;
	    }
	}

	return resultArray;
    }

    public Object[][] getAsArray(List<String> columns) {
	int rowCount = getRowCount();

	Object[][] resultArray = new Object[rowCount + 1][columns.size()];

	resultArray[0] = columns.toArray();
	Object cell;
	for (int row = 0; row < rowCount; ++row) {
	    for (int col = 0; col < columns.size(); ++col) {
		cell = getCell(columns.get(col), row);
		if (cell instanceof Float
			&& ((Float) cell).floatValue() % 1 == 0) {
		    cell = ((Float) cell).longValue();
		}
		resultArray[row + 1][col] = cell;
	    }
	}

	return resultArray;
    }

    public String toHtmlString() {
	return parseToString("\t", "<br>").toString();
    }

    @Override
    public String toString() {
	return parseToString("\t", "\n").toString();
    }

    private StringBuilder parseToString(String space, String enter) {
	StringBuilder sb = new StringBuilder();
	for (String column : getColumnNames()) {
	    sb.append(column).append(space);
	}

	for (int i = 0; i < getRowCount(); ++i) {
	    sb.append(enter);
	    for (String column : getColumnNames()) {
		sb.append(getCell(column, i).toString()).append(space);
	    }
	}

	return sb;
    }
}
